React - fetch gebruiken in een bestaande component
Als je nieuwe functionaliteit aan een bestaande component wilt toevoegen, denk dan in 'knopen' die herbruikbaar zijn. De nieuwe functionaliteit moet zo worden toegevoegd dat vroegere code nog altijd werkt.
Probleem
We hebben een LikePanel
klasse component gemaakt. Telkens de gebruiker op de knop klikt wordt de teller, die de likes bijhoudt, met 1 vermeerderd en wordt dit resultaat in de browser getoond.
Nu willen we twee mogelijkheden toevoegen:
- het aantal likes uit een tabel in de database ophalen;
- als er op de Like-knop in de
LikePanel
geklikt wordt moet de nieuwe waarde van het aantal likes in de tabel in de database opgeslagen worden;
Wijzigingen MmtApi
- Wanneer er voor de key nog geen rij in de tabel bestaat, retourneer een
MmtLike
instantie metLikes
ingesteld op 0.- Daarvoor voegen we eerst een constructor overload toe aan de
MmtLike
modelklasse:public MmtLike(string key) { this.Id = 0; this.Key = key; this.Name = "niet van toepassing"; this.Likes = 0; }
- In de
MmtLineController
moet de get methode een instantie van de modelklasse retourneren metLikes
ingesteld op 0 als er nog geen rij voor dit artikel in deLikes
tabel aanwezig is. Nu retourneert die methode een null waarde indien dit het geval is, en dat genereert een fout in de client code. Er wordt slechts een rij in de tabelLikes
gemaakt wanneer een post wordt uitgevoerd met eenkey
-waarde die nog niet bestaat.
We gebruiken hiervoor de constructor die we net hebben toegevoegd aan de modelklasse:[HttpGet("{key}")] public MmtLike GetLikes(string key) { var mmtLike = mmtContext.MmtLikes.Where(a => a.Key == key).FirstOrDefault(); mmtLike = mmtLike == null ? new MmtLike(key) : mmtLike; return mmtLike; }
- Vergeet niet een lege constructor toe te voegen als je nog van de default constructor gebruik wilt maken:
public MmtLike() { }
- In de
MmtLineController
retourneert de post methode een instantie van de modelklasse ingesteld opnull
als er nog geen rij voor dit artikel in deLikes
tabel aanwezig is. De post methode maakt echter een rij in de tabelMmt
en moet dus die waarde retourneren:Likes
[HttpPost] public MmtLike PostLike(MmtLike item) { var mmtLike = mmtContext.MmtLikes.Where(a => a.Key == item.Key).FirstOrDefault(); if (mmtLike == null) { mmtContext.MmtLikes.Add(item); mmtContext.SaveChanges(); mmtLike = item; } else { mmtLike.Likes = mmtLike.Likes + 1; mmtContext.MmtLikes.Update(mmtLike); mmtContext.SaveChanges(); } return mmtLike; }
- Daarvoor voegen we eerst een constructor overload toe aan de
Wijzigingen mmt-react client
We voegen een keyValue
attribuut in de JSX tag van <LikePanel />
.
- Op basis daarvan gaat de
LikePanel
component beslissen of data uit de databank gehaald moet worden of niet. Op die manier zal deLikePanel
, die in oudere code al werd gebruikt, nog steeds werken. In de ArticleDetail component, die staat in het in ui-article.cs bestand voegen we een attribuut toe aan de<LikePanel/>
tag. We geven dekey
eigenschap van het artikel mee dat we in detail willen tonen. Het is de waarde die we gebruiken om de rij in deMmtLikes
tabel op te zoeken:<LikePanel keyValue={this.props.article.key}/>
- We declareren bovenaan een eigenschap waarin we de url van de MmtApi opslaan:
class LikePanel extends React.Component { host = "http://localhost:58013/MmtLike";
- We voegen de methode
getLikes
toe aan deLikePanel
componentklasse. De get wordt alleen uitgevoerd als hetkeyValue
attribuut gedefinieerd is. Op de manier zal de legacy code nog blijven werken:getLikes = () => { const keyValue = this.props.keyValue; let count = 0; if (typeof keyValue !== 'undefined') { // als de callback wordt uitgevoerd, is this niet meer in de scope // daarom slaan we die op in een constante en geven die met de callback mee const self = this; const url = `${this.host}/${keyValue}`; fetch(url) .then(response => response.json()) .then(data => { this.setState({ likes: data.likes });}); } }
- En we roepen die op in de constructor van de
LikePanel
componentklasse:constructor(props) { super(props); // Now 'this' is initialized by calling the parent constructor. this.state = { likes: 0 }; this.getLikes(); }
- We voegen een methode toe met de naam
postLikes
- We beginnen met het helpers.js bestand te laden, want daarin staat de
postData
methode:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script src="js/helpers.js"></script> <script type="text/babel" src="js/ui-controls.js"></script>
- We voegen de methode
postLikes
toe in deLikePanel
componentklasse:postLikes = () => { let item = { Key: this.props.keyValue, Name: 'onbelangrijk', Likes: 1 }; postData(this.host, item) .then(data => { this.setState({ likes: data.likes }); }); }
- We roepen de methode postlikes op in de incrementLike methode, alleen als het keyValue attribuut gedefinieerd is, posten we naar de database. Op die manier houden we rekening met legacy code:
incrementLike = () => { const keyValue = this.props.keyValue; if (typeof keyValue !== 'undefined') { this.postLikes(); } else { let newCount = this.state.likes + 1; this.setState({ likes: newCount }); } };
Als ondertussen deLikes
kolom in deMmtLikes
tabel door andere gebruiker al werd geüpdated, zal deze nieuwe waarde hier ook getoond worden.
- We beginnen met het helpers.js bestand te laden, want daarin staat de
Uitproberen
- Run de API in Visual Studio (F5). In het bestand launchSettings.json vind je het poortnummer dat door Visual Studio werd ingeteld:
{ "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:58013", "sslPort": 0 }
- Noteer de poort en kopieer die in de url in de
LikePanel
componentklasse:class LikePanel extends React.Component { host = "http://localhost:58013/MmtLike";
- Als je met een lokale MySql server werkt, moet die opgestart zijn. De remote MySQL server runt altijd.
- Start de mmt-react app in de terminal Visual Code met:
php -S localhost:63344
Gebruik een vrije poort naar keuze.
- Open de mmt-react app in de browser door de volgende url in te typen:
http://localhost:63344/
- De code staat in de mmt-react map op Bitbucket.
2020-05-18 15:49:07